﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using SyntaxHighlight;

namespace TestApp.Boo
{
    public class BooTokenParser : ISyntaxLexer
    {
        public BooTokenParser()
        {
            
        }
        

        public override void Parse(string text, int caret_position)
        {
            _tokens.Clear();

            if (text != String.Empty)
            {

                antlr.TokenStream s = BooTestLexer.CreateLexer(text);

                try
                {
                    antlr.IToken token = s.nextToken();
                    int start_ml_comment = -1;

                    while (token.Type != BooTestLexer.EOF)
                    {
                        // multiline comment
                        if (token.Type == BooTestLexer.ML_COMMENT)
                        {
                            int end = -1;
                            int start = start_ml_comment;

                            if (start_ml_comment == -1)
                            {
                                start_ml_comment = GetTextIndexFromLine(text, token.getLine(), token.getColumn());
                                start = start_ml_comment;
                            }

                            if (start_ml_comment != -1 && token.getFilename() == "LEAVINGML_COMMENT")
                            {
                                end = GetTextIndexFromLine(text, token.getLine(), token.getColumn() + token.getText().Length);
                                start = start_ml_comment;
                                start_ml_comment = -1;
                            }

                            if (start != -1 && end != -1)
                            {
                                CodeToken ct = new CodeToken();
                                ct.TokenType = CodeTokenType.Comment;
                                ct.Start = start;
                                ct.End = end;
                                _tokens.Add(ct);
                            } // multiline comment                          
                        }



                        if (start_ml_comment == -1)
                        {
                            // keywords
                            if (IsKeyword(token.Type))
                            {
                                CodeToken ct = new CodeToken();
                                ct.TokenType = CodeTokenType.Keyword;
                                ct.Start = GetTextIndexFromLine(text, token.getLine(), token.getColumn());
                                ct.End = GetTextIndexFromLine(text, token.getLine(), token.getColumn() + token.getText().Length);
                                _tokens.Add(ct);
                            }

                            // strings
                            if (token.Type == BooTestLexer.DOUBLE_QUOTED_STRING || token.Type == BooTestLexer.SINGLE_QUOTED_STRING)
                            {
                                CodeToken ct = new CodeToken();
                                ct.TokenType = CodeTokenType.String;
                                ct.Start = GetTextIndexFromLine(text, token.getLine(), token.getColumn());
                                if (ct.Start < 0)
                                    ct.Start = 0;
                                ct.End = GetTextIndexFromLine(text, token.getLine(), token.getColumn() + token.getText().Length + 2);
                                _tokens.Add(ct);
                            }

                            // strings """triple quoted strings"""
                            if (token.Type == BooTestLexer.TRIPLE_QUOTED_STRING)
                            {
                                CodeToken ct = new CodeToken();
                                ct.TokenType = CodeTokenType.String;
                                ct.Start = GetTextIndexFromLine(text, token.getLine(), token.getColumn());
                                if (ct.Start < 0)
                                    ct.Start = 0;
                                ct.End = GetTextIndexFromLine(text, token.getLine(), token.getColumn() + token.getText().Length + 6);
                                _tokens.Add(ct);
                            }

                            // sigle line comment
                            if (token.Type == BooTestLexer.SL_COMMENT)
                            {
                                CodeToken ct = new CodeToken();
                                ct.TokenType = CodeTokenType.Comment;
                                ct.Start = GetTextIndexFromLine(text, token.getLine(), token.getColumn());
                                ct.End = GetTextIndexFromLine(text, token.getLine(), token.getColumn() + token.getText().Length);
                                _tokens.Add(ct);
                            }

                            // number
                            if (token.Type == BooTestLexer.INT || token.Type == BooTestLexer.DOUBLE || token.Type == BooTestLexer.FLOAT || token.Type == BooTestLexer.LONG)
                            {
                                CodeToken ct = new CodeToken();  
                                ct.TokenType = CodeTokenType.Number;
                                ct.Start = GetTextIndexFromLine(text, token.getLine(), token.getColumn());
                                ct.End = GetTextIndexFromLine(text, token.getLine(), token.getColumn() + token.getText().Length);
                                _tokens.Add(ct);
                            }

                            // identifier
                            if (token.Type == BooTestLexer.ID)
                            {
                                CodeToken ct = new CodeToken();
                                ct.TokenType = CodeTokenType.Indentifier;
                                ct.Start = GetTextIndexFromLine(text, token.getLine(), token.getColumn());
                                ct.End = GetTextIndexFromLine(text, token.getLine(), token.getColumn() + token.getText().Length);
                                _tokens.Add(ct);
                            }
                        }

                     
                        
                       
                        token = s.nextToken();
                    }
                }
                catch
                {
                    return;
                }
            }
        }

        /// <summary>
        /// Return true type is a keyword 
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        private bool IsKeyword(int type)
        {
            if (type == BooTestLexer.ABSTRACT
            || type == BooTestLexer.AND
            || type == BooTestLexer.AS
            || type == BooTestLexer.BREAK
            || type == BooTestLexer.CALLABLE
            || type == BooTestLexer.CAST
            || type == BooTestLexer.CHAR
            || type == BooTestLexer.CLASS
            || type == BooTestLexer.CONSTRUCTOR
            || type == BooTestLexer.CONTINUE
            || type == BooTestLexer.DEF
            || type == BooTestLexer.DESTRUCTOR
            || type == BooTestLexer.DO
            || type == BooTestLexer.ELIF
            || type == BooTestLexer.ELSE
            || type == BooTestLexer.ENSURE
            || type == BooTestLexer.ENUM
            || type == BooTestLexer.EVENT
            || type == BooTestLexer.EXCEPT
            || type == BooTestLexer.FAILURE
            || type == BooTestLexer.FINAL
            || type == BooTestLexer.FROM
            || type == BooTestLexer.FOR
            || type == BooTestLexer.FALSE
            || type == BooTestLexer.GET
            || type == BooTestLexer.GOTO
            || type == BooTestLexer.IF
            || type == BooTestLexer.IMPORT
            || type == BooTestLexer.IN
            || type == BooTestLexer.INTERFACE
            || type == BooTestLexer.INTERNAL
            || type == BooTestLexer.IS
            || type == BooTestLexer.ISA
            || type == BooTestLexer.NOT
            || type == BooTestLexer.NULL
            || type == BooTestLexer.OF
            || type == BooTestLexer.OR
            || type == BooTestLexer.OVERRIDE
            || type == BooTestLexer.NAMESPACE
            || type == BooTestLexer.PARTIAL
            || type == BooTestLexer.PASS
            || type == BooTestLexer.PUBLIC
            || type == BooTestLexer.PROTECTED
            || type == BooTestLexer.PRIVATE
            || type == BooTestLexer.RAISE
            || type == BooTestLexer.REF
            || type == BooTestLexer.RETURN
            || type == BooTestLexer.SELF
            || type == BooTestLexer.SET 
            || type == BooTestLexer.WHILE
            || type == BooTestLexer.TRUE
                )
                return true;


            return false;
        }

        /// <summary>
        /// Transform column/line position into index string position
        /// </summary>
        /// <param name="text"></param>
        /// <param name="line"></param>
        /// <param name="column"></param>
        /// <returns></returns>
        private int GetTextIndexFromLine(string text, int line, int column)
        {
            int index = 0;
            for (int i = 0; i < line-1; i++)
            {
                int found = text.IndexOf("\n", index);
                if (found != -1)
                {
                    index = found+1;
                }
            }
            return index + column-1;
        }

        public override System.Windows.Input.Key SuggestionListTriggerKey
        {
            get 
            {
                return System.Windows.Input.Key.OemPeriod;
            }
        }

        public override bool CanShowSuggestionList(int caret_position)
        {
            return true;
        }
    }
}
